using Admin.NET.Application.Entity;
using Admin.NET.Core;
using Furion.DependencyInjection;
using Microsoft.AspNetCore.Authorization;
using SqlSugar;

namespace Admin.NET.Application.Service.Report;

/// <summary>
/// 盘点统计报表（盘点次数、盘盈/亏数量与金额、准确率）
/// </summary>
[ApiDescriptionSettings("Report", Name = "stocktaking", Order = 902)]
[Route("api/report/stocktaking")]
[AllowAnonymous]
public class StocktakingReportService : IDynamicApiController, ITransient
{
	private readonly ISqlSugarClient _sqlSugarClient;

	public StocktakingReportService(ISqlSugarClient sqlSugarClient)
	{
		_sqlSugarClient = sqlSugarClient;
	}

	/// <summary>
	/// 盘点统计分页（按盘点时间范围、仓库、物品模糊筛选）
	/// </summary>
	[HttpPost("page")]
	public async Task<object> Page([FromBody] GetStocktakingInput input)
	{
		DateTime? start = input.StartTime?.Date;
		DateTime? end = input.EndTime?.Date;
		if (end != null) end = end.Value.AddDays(1).AddTicks(-1);

        // 使用“有效时间”参与筛选：EndTime(优先) → StartTime → CreateTime
        var query = _sqlSugarClient.Queryable<Sysstocktakingorder>()
            .WhereIF(start != null, x => SqlFunc.IsNull(x.EndTime, SqlFunc.IsNull(x.StartTime, x.CreateTime)) >= start)
            .WhereIF(end != null, x => SqlFunc.IsNull(x.EndTime, SqlFunc.IsNull(x.StartTime, x.CreateTime)) <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.WarehouseName), x => x.WarehouseName!.Contains(input.WarehouseName!))
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), x => x.GoodsName!.Contains(input.GoodsOrCategory!))
			.LeftJoin<SysOrg>((o, org) => o.OrgId == org.Id)
			.Select((o, org) => new StocktakingRowOutput
			{
				BillNo = o.Code,
				StartTime = o.StartTime,
				EndTime = o.EndTime,
				WarehouseName = o.WarehouseName,
				InventoryResult = o.InventoryResult,
				GoodsName = o.GoodsName,
				Quantity = o.Quantity,
				ProfitQuantity = o.ProfitQuantity,
				LossQuantity = o.LossQuantity,
				ProfitAmount = o.ProfitAmount,
				LossAmount = o.LossAmount,
				MakerName = o.CreateUserName,
				DeptName = org.Name,
				MakeTime = o.CreateTime,
				Remark = o.Remark
			});

		var total = new RefAsync<int>();
		var list = await query.ToPageListAsync(input.Page, input.PageSize, total);

		return new { result = new { items = list, total = total.Value, page = input.Page, pageSize = input.PageSize } };
	}

	/// <summary>
	/// 盘点统计汇总（次数、盘盈/亏数量金额、准确率）
	/// </summary>
	[HttpPost("stats")]
	public async Task<object> Stats([FromBody] GetStocktakingInput input)
	{
		DateTime? start = input.StartTime?.Date;
		DateTime? end = input.EndTime?.Date;
		if (end != null) end = end.Value.AddDays(1).AddTicks(-1);

        var src = _sqlSugarClient.Queryable<Sysstocktakingorder>()
            .WhereIF(start != null, x => SqlFunc.IsNull(x.EndTime, SqlFunc.IsNull(x.StartTime, x.CreateTime)) >= start)
            .WhereIF(end != null, x => SqlFunc.IsNull(x.EndTime, SqlFunc.IsNull(x.StartTime, x.CreateTime)) <= end)
			.WhereIF(!string.IsNullOrWhiteSpace(input.WarehouseName), x => x.WarehouseName!.Contains(input.WarehouseName!))
			.WhereIF(!string.IsNullOrWhiteSpace(input.GoodsOrCategory), x => x.GoodsName!.Contains(input.GoodsOrCategory!));

		var count = await src.CountAsync();
		var data = await src.Select(x => new { 
			x.Quantity, 
			x.ProfitQuantity, 
			x.LossQuantity, 
			x.ProfitAmount, 
			x.LossAmount 
		}).ToListAsync();

		int totalQty = data.Sum(x => x.Quantity ?? 0);
		int profitQty = data.Sum(x => x.ProfitQuantity ?? 0);
		int lossQty = data.Sum(x => x.LossQuantity ?? 0);
		decimal profitAmt = data.Sum(x => x.ProfitAmount ?? 0);
		decimal lossAmt = data.Sum(x => x.LossAmount ?? 0);
		int diffQty = Math.Abs(profitQty - lossQty);
		double accuracy = totalQty > 0 ? Math.Max(0, 1 - (double)diffQty / totalQty) : 1;

		return new { result = new StocktakingStatsOutput
		{
			Count = count,
			TotalQuantity = totalQty,
			ProfitQuantity = profitQty,
			LossQuantity = lossQty,
			ProfitAmount = profitAmt,
			LossAmount = lossAmt,
			AccuracyRate = Math.Round(accuracy, 4)
		}};
	}
}

public class GetStocktakingInput
{
	public DateTime? StartTime { get; set; }
	public DateTime? EndTime { get; set; }
	public string? WarehouseName { get; set; }
	public string? GoodsOrCategory { get; set; }
	public int Page { get; set; } = 1;
	public int PageSize { get; set; } = 10;
}

public class StocktakingRowOutput
{
	public string BillNo { get; set; } = string.Empty;
	public DateTime? StartTime { get; set; }
	public DateTime? EndTime { get; set; }
	public string? WarehouseName { get; set; }
	public string? InventoryResult { get; set; }
	public string? GoodsName { get; set; }
	public int? Quantity { get; set; }
	public int? ProfitQuantity { get; set; }
	public int? LossQuantity { get; set; }
	public decimal? ProfitAmount { get; set; }
	public decimal? LossAmount { get; set; }
	public string? MakerName { get; set; }
	public string? DeptName { get; set; }
	public DateTime? MakeTime { get; set; }
	public string? Remark { get; set; }
}

public class StocktakingStatsOutput
{
	public int Count { get; set; }
	public int TotalQuantity { get; set; }
	public int ProfitQuantity { get; set; }
	public int LossQuantity { get; set; }
	public decimal ProfitAmount { get; set; }
	public decimal LossAmount { get; set; }
	public double AccuracyRate { get; set; }
}


